home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevxini.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  31.9 KB  |  1,007 lines

  1. /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevxini.c,v 1.9 2000/09/19 19:00:23 lpd Exp $ */
  20. /* X Windows driver initialization/finalization */
  21. #include "memory_.h"
  22. #include "x_.h"
  23. #include "gx.h"
  24. #include "gserrors.h"
  25. #include "gxdevice.h"
  26. #include "gxdevmem.h"
  27. #include "gsparamx.h"
  28. #include "gdevbbox.h"
  29. #include "gdevx.h"
  30.  
  31. extern char *getenv(P1(const char *));
  32.  
  33. extern const gx_device_bbox gs_bbox_device;
  34. extern const gx_device_X gs_x11_device;
  35.  
  36. extern const gx_device_bbox_procs_t gdev_x_box_procs;
  37.  
  38. /* Define constants for orientation from ghostview */
  39. /* Number represents clockwise rotation of the paper in degrees */
  40. typedef enum {
  41.     Portrait = 0,        /* Normal portrait orientation */
  42.     Landscape = 90,        /* Normal landscape orientation */
  43.     Upsidedown = 180,        /* Don't think this will be used much */
  44.     Seascape = 270        /* Landscape rotated the wrong way */
  45. } orientation;
  46.  
  47. /* GC descriptors */
  48. private_st_x11fontmap();
  49.  
  50. /* ---------------- Opening/initialization ---------------- */
  51.  
  52. /* Forward references */
  53. private void gdev_x_setup_fontmap(P1(gx_device_X *));
  54.  
  55. /* Catch the alloc error when there is not enough resources for the
  56.  * backing pixmap.  Automatically shut off backing pixmap and let the
  57.  * user know when this happens.
  58.  *
  59.  * Because the X API was designed without adequate thought to reentrancy,
  60.  * these variables must be allocated statically.  We do not see how this
  61.  * code can work reliably in the presence of multi-threading.
  62.  */
  63. private struct xv_ {
  64.     Boolean alloc_error;
  65.     XErrorHandler orighandler;
  66.     XErrorHandler oldhandler;
  67. } x_error_handler;
  68.  
  69. private int
  70. x_catch_alloc(Display * dpy, XErrorEvent * err)
  71. {
  72.     if (err->error_code == BadAlloc)
  73.     x_error_handler.alloc_error = True;
  74.     if (x_error_handler.alloc_error)
  75.     return 0;
  76.     return x_error_handler.oldhandler(dpy, err);
  77. }
  78.  
  79. int
  80. x_catch_free_colors(Display * dpy, XErrorEvent * err)
  81. {
  82.     if (err->request_code == X_FreeColors)
  83.     return 0;
  84.     return x_error_handler.orighandler(dpy, err);
  85. }
  86.  
  87. /* Open the X device */
  88. int
  89. gdev_x_open(gx_device_X * xdev)
  90. {
  91.     XSizeHints sizehints;
  92.     char *window_id;
  93.     XEvent event;
  94.     XVisualInfo xvinfo;
  95.     int nitems;
  96.     XtAppContext app_con;
  97.     Widget toplevel;
  98.     Display *dpy;
  99.     XColor xc;
  100.     int zero = 0;
  101.     int xid_height, xid_width;
  102.     int code;
  103.  
  104. #ifdef DEBUG
  105. # ifdef have_Xdebug
  106.     if (gs_debug['X']) {
  107.     extern int _Xdebug;
  108.  
  109.     _Xdebug = 1;
  110.     }
  111. # endif
  112. #endif
  113.     if (!(xdev->dpy = XOpenDisplay((char *)NULL))) {
  114.     char *dispname = getenv("DISPLAY");
  115.  
  116.     eprintf1("Cannot open X display `%s'.\n",
  117.          (dispname == NULL ? "(null)" : dispname));
  118.     return_error(gs_error_ioerror);
  119.     }
  120.     xdev->dest = 0;
  121.     if ((window_id = getenv("GHOSTVIEW"))) {
  122.     if (!(xdev->ghostview = sscanf(window_id, "%ld %ld",
  123.                        &(xdev->win), &(xdev->dest)))) {
  124.         eprintf("Cannot get Window ID from ghostview.\n");
  125.         return_error(gs_error_ioerror);
  126.     }
  127.     }
  128.     if (xdev->pwin != (Window) None) {    /* pick up the destination window parameters if specified */
  129.     XWindowAttributes attrib;
  130.  
  131.     xdev->win = xdev->pwin;
  132.     if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
  133.         xdev->scr = attrib.screen;
  134.         xvinfo.visual = attrib.visual;
  135.         xdev->cmap = attrib.colormap;
  136.         xid_width = attrib.width;
  137.         xid_height = attrib.height;
  138.     } else {
  139.         /* No idea why we can't get the attributes, but */
  140.         /* we shouldn't let it lead to a failure below. */
  141.         xid_width = xid_height = 0;
  142.     }
  143.     } else if (xdev->ghostview) {
  144.     XWindowAttributes attrib;
  145.     Atom type;
  146.     int format;
  147.     unsigned long nitems, bytes_after;
  148.     char *buf;
  149.     Atom ghostview_atom = XInternAtom(xdev->dpy, "GHOSTVIEW", False);
  150.  
  151.     if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
  152.         xdev->scr = attrib.screen;
  153.         xvinfo.visual = attrib.visual;
  154.         xdev->cmap = attrib.colormap;
  155.         xdev->width = attrib.width;
  156.         xdev->height = attrib.height;
  157.     }
  158.     /* Delete property if explicit dest is given */
  159.     if (XGetWindowProperty(xdev->dpy, xdev->win, ghostview_atom, 0,
  160.                    256, (xdev->dest != 0), XA_STRING,
  161.                    &type, &format, &nitems, &bytes_after,
  162.                    (unsigned char **)&buf) == 0 &&
  163.         type == XA_STRING) {
  164.         int llx, lly, urx, ury;
  165.         int left_margin = 0, bottom_margin = 0;
  166.         int right_margin = 0, top_margin = 0;
  167.  
  168.         /* We declare page_orientation as an int so that we can */
  169.         /* use an int * to reference it for sscanf; compilers */
  170.         /* might be tempted to use less space to hold it if */
  171.         /* it were declared as an orientation. */
  172.         int /*orientation */ page_orientation;
  173.         float xppp, yppp;    /* pixels per point */
  174.  
  175.         nitems = sscanf(buf,
  176.                 "%ld %d %d %d %d %d %f %f %d %d %d %d",
  177.                 &(xdev->bpixmap), &page_orientation,
  178.                 &llx, &lly, &urx, &ury,
  179.                 &(xdev->x_pixels_per_inch),
  180.                 &(xdev->y_pixels_per_inch),
  181.                 &left_margin, &bottom_margin,
  182.                 &right_margin, &top_margin);
  183.         if (!(nitems == 8 || nitems == 12)) {
  184.         eprintf("Cannot get ghostview property.\n");
  185.         return_error(gs_error_ioerror);
  186.         }
  187.         if (xdev->dest && xdev->bpixmap) {
  188.         eprintf("Both destination and backing pixmap specified.\n");
  189.         return_error(gs_error_rangecheck);
  190.         }
  191.         if (xdev->dest) {
  192.         Window root;
  193.         int x, y;
  194.         unsigned int width, height;
  195.         unsigned int border_width, depth;
  196.  
  197.         if (XGetGeometry(xdev->dpy, xdev->dest, &root, &x, &y,
  198.                  &width, &height, &border_width, &depth)) {
  199.             xdev->width = width;
  200.             xdev->height = height;
  201.         }
  202.         }
  203.         xppp = xdev->x_pixels_per_inch / 72.0;
  204.         yppp = xdev->y_pixels_per_inch / 72.0;
  205.         switch (page_orientation) {
  206.         case Portrait:
  207.             xdev->initial_matrix.xx = xppp;
  208.             xdev->initial_matrix.xy = 0.0;
  209.             xdev->initial_matrix.yx = 0.0;
  210.             xdev->initial_matrix.yy = -yppp;
  211.             xdev->initial_matrix.tx = -llx * xppp;
  212.             xdev->initial_matrix.ty = ury * yppp;
  213.             break;
  214.         case Landscape:
  215.             xdev->initial_matrix.xx = 0.0;
  216.             xdev->initial_matrix.xy = yppp;
  217.             xdev->initial_matrix.yx = xppp;
  218.             xdev->initial_matrix.yy = 0.0;
  219.             xdev->initial_matrix.tx = -lly * xppp;
  220.             xdev->initial_matrix.ty = -llx * yppp;
  221.             break;
  222.         case Upsidedown:
  223.             xdev->initial_matrix.xx = -xppp;
  224.             xdev->initial_matrix.xy = 0.0;
  225.             xdev->initial_matrix.yx = 0.0;
  226.             xdev->initial_matrix.yy = yppp;
  227.             xdev->initial_matrix.tx = urx * xppp;
  228.             xdev->initial_matrix.ty = -lly * yppp;
  229.             break;
  230.         case Seascape:
  231.             xdev->initial_matrix.xx = 0.0;
  232.             xdev->initial_matrix.xy = -yppp;
  233.             xdev->initial_matrix.yx = -xppp;
  234.             xdev->initial_matrix.yy = 0.0;
  235.             xdev->initial_matrix.tx = ury * xppp;
  236.             xdev->initial_matrix.ty = urx * yppp;
  237.             break;
  238.         }
  239.  
  240.         /* The following sets the imageable area according to the */
  241.         /* bounding box and margins sent by ghostview.            */
  242.         /* This code has been patched many times; its current state */
  243.         /* is per a recommendation by Tim Theisen on 4/28/95. */
  244.  
  245.         xdev->ImagingBBox[0] = llx - left_margin;
  246.         xdev->ImagingBBox[1] = lly - bottom_margin;
  247.         xdev->ImagingBBox[2] = urx + right_margin;
  248.         xdev->ImagingBBox[3] = ury + top_margin;
  249.         xdev->ImagingBBox_set = true;
  250.  
  251.     } else if (xdev->pwin == (Window) None) {
  252.         eprintf("Cannot get ghostview property.\n");
  253.         return_error(gs_error_ioerror);
  254.     }
  255.     } else {
  256.     Screen *scr = DefaultScreenOfDisplay(xdev->dpy);
  257.  
  258.     xdev->scr = scr;
  259.     xvinfo.visual = DefaultVisualOfScreen(scr);
  260.     xdev->cmap = DefaultColormapOfScreen(scr);
  261.     if (xvinfo.visual->class != TrueColor) {
  262.         int scrno = DefaultScreen(xdev->dpy);
  263.         if ( XMatchVisualInfo(xdev->dpy, scrno, 24, TrueColor, &xvinfo) ||
  264.          XMatchVisualInfo(xdev->dpy, scrno, 32, TrueColor, &xvinfo) || 
  265.          XMatchVisualInfo(xdev->dpy, scrno, 16, TrueColor, &xvinfo) ||
  266.          XMatchVisualInfo(xdev->dpy, scrno, 15, TrueColor, &xvinfo)  ) {
  267.         xdev->cmap = XCreateColormap (xdev->dpy, 
  268.                           DefaultRootWindow(xdev->dpy),
  269.                           xvinfo.visual, AllocNone ); 
  270.         }
  271.     }
  272.     }
  273.     xvinfo.visualid = XVisualIDFromVisual(xvinfo.visual);
  274.     xdev->vinfo = XGetVisualInfo(xdev->dpy, VisualIDMask, &xvinfo, &nitems);
  275.     if (xdev->vinfo == NULL) {
  276.     eprintf("Cannot get XVisualInfo.\n");
  277.     return_error(gs_error_ioerror);
  278.     }
  279.     /* Buggy X servers may cause a Bad Access on XFreeColors. */
  280.     x_error_handler.orighandler = XSetErrorHandler(x_catch_free_colors);
  281.  
  282.     /* Get X Resources.  Use the toolkit for this. */
  283.     XtToolkitInitialize();
  284.     app_con = XtCreateApplicationContext();
  285.     XtAppSetFallbackResources(app_con, gdev_x_fallback_resources);
  286.     dpy = XtOpenDisplay(app_con, NULL, "ghostscript", "Ghostscript",
  287.             NULL, 0, &zero, NULL);
  288.     toplevel = XtAppCreateShell(NULL, "Ghostscript",
  289.                 applicationShellWidgetClass, dpy, NULL, 0);
  290.     XtGetApplicationResources(toplevel, (XtPointer) xdev,
  291.                   gdev_x_resources, gdev_x_resource_count,
  292.                   NULL, 0);
  293.  
  294.     /* Reserve foreground and background colors under the regular connection. */
  295.     xc.pixel = xdev->foreground;
  296.     XQueryColor(xdev->dpy, DefaultColormap(xdev->dpy,DefaultScreen(xdev->dpy)), &xc);
  297.     XAllocColor(xdev->dpy, xdev->cmap, &xc);
  298.     xdev->foreground = xc.pixel;
  299.     xc.pixel = xdev->background;
  300.     XQueryColor(xdev->dpy, DefaultColormap(xdev->dpy,DefaultScreen(xdev->dpy)), &xc);
  301.     XAllocColor(xdev->dpy, xdev->cmap, &xc);
  302.     xdev->background = xc.pixel;
  303.  
  304.     code = gdev_x_setup_colors(xdev);
  305.     if (code < 0) {
  306.     XCloseDisplay(xdev->dpy);
  307.     return code;
  308.     }
  309.     gdev_x_setup_fontmap(xdev);
  310.  
  311.     if (!xdev->ghostview) {
  312.     XWMHints wm_hints;
  313.     XSetWindowAttributes xswa;
  314.     gx_device *dev = (gx_device *) xdev;
  315.  
  316.     /* Take care of resolution and paper size. */
  317.     if (xdev->x_pixels_per_inch == FAKE_RES ||
  318.         xdev->y_pixels_per_inch == FAKE_RES) {
  319.         float xsize = (float)xdev->width / xdev->x_pixels_per_inch;
  320.         float ysize = (float)xdev->height / xdev->y_pixels_per_inch;
  321.  
  322.         if (xdev->xResolution == 0.0 && xdev->yResolution == 0.0) {
  323.         float dpi, xdpi, ydpi;
  324.  
  325.         xdpi = 25.4 * WidthOfScreen(xdev->scr) /
  326.             WidthMMOfScreen(xdev->scr);
  327.         ydpi = 25.4 * HeightOfScreen(xdev->scr) /
  328.             HeightMMOfScreen(xdev->scr);
  329.         dpi = min(xdpi, ydpi);
  330.         /*
  331.          * Some X servers provide very large "virtual screens", and
  332.          * return the virtual screen size for Width/HeightMM but the
  333.          * physical size for Width/Height.  Attempt to detect and
  334.          * correct for this now.  This is a KLUDGE required because
  335.          * the X server provides no way to read the screen
  336.          * resolution directly.
  337.          */
  338.         if (dpi < 30)
  339.             dpi = 75;    /* arbitrary */
  340.         else {
  341.             while (xsize * dpi > WidthOfScreen(xdev->scr) - 32 ||
  342.                ysize * dpi > HeightOfScreen(xdev->scr) - 32)
  343.             dpi *= 0.95;
  344.         }
  345.         xdev->x_pixels_per_inch = dpi;
  346.         xdev->y_pixels_per_inch = dpi;
  347.         } else {
  348.         xdev->x_pixels_per_inch = xdev->xResolution;
  349.         xdev->y_pixels_per_inch = xdev->yResolution;
  350.         }
  351.         if (xdev->width > WidthOfScreen(xdev->scr)) {
  352.         xdev->width = xsize * xdev->x_pixels_per_inch;
  353.         }
  354.         if (xdev->height > HeightOfScreen(xdev->scr)) {
  355.         xdev->height = ysize * xdev->y_pixels_per_inch;
  356.         }
  357.         xdev->MediaSize[0] =
  358.         (float)xdev->width / xdev->x_pixels_per_inch * 72;
  359.         xdev->MediaSize[1] =
  360.         (float)xdev->height / xdev->y_pixels_per_inch * 72;
  361.     }
  362.     sizehints.x = 0;
  363.     sizehints.y = 0;
  364.     sizehints.width = xdev->width;
  365.     sizehints.height = xdev->height;
  366.     sizehints.flags = 0;
  367.  
  368.     if (xdev->geometry != NULL) {
  369.         /*
  370.          * Note that border_width must be set first.  We can't use
  371.          * scr, because that is a Screen*, and XWMGeometry wants
  372.          * the screen number.
  373.          */
  374.         char gstr[40];
  375.         int bitmask;
  376.  
  377.         sprintf(gstr, "%dx%d+%d+%d", sizehints.width,
  378.             sizehints.height, sizehints.x, sizehints.y);
  379.         bitmask = XWMGeometry(xdev->dpy, DefaultScreen(xdev->dpy),
  380.                   xdev->geometry, gstr, xdev->borderWidth,
  381.                   &sizehints,
  382.                   &sizehints.x, &sizehints.y,
  383.                   &sizehints.width, &sizehints.height,
  384.                   &sizehints.win_gravity);
  385.  
  386.         if (bitmask & (XValue | YValue))
  387.         sizehints.flags |= USPosition;
  388.     }
  389.     gx_default_get_initial_matrix(dev, &(xdev->initial_matrix));
  390.  
  391.     if (xdev->pwin != (Window) None && xid_width != 0 && xid_height != 0) {
  392. #if 0                /*************** */
  393.  
  394.         /*
  395.          * The user who originally implemented the WindowID feature
  396.          * provided the following code to scale the displayed output
  397.          * to fit in the window.  We think this is a bad idea,
  398.          * since it doesn't track window resizing and is generally
  399.          * completely at odds with the way Ghostscript treats
  400.          * window or paper size in all other contexts.  We are
  401.          * leaving the code here in case someone decides that
  402.          * this really is the behavior they want.
  403.          */
  404.  
  405.         /* Scale to fit in the window. */
  406.         xdev->initial_matrix.xx
  407.         = xdev->initial_matrix.xx *
  408.         (float)xid_width / (float)xdev->width;
  409.         xdev->initial_matrix.yy
  410.         = xdev->initial_matrix.yy *
  411.         (float)xid_height / (float)xdev->height;
  412.  
  413. #endif /*************** */
  414.         xdev->width = xid_width;
  415.         xdev->height = xid_height;
  416.         xdev->initial_matrix.ty = xdev->height;
  417.     } else {        /* !xdev->pwin */
  418.         xswa.event_mask = ExposureMask;
  419.         xswa.background_pixel = xdev->background;
  420.         xswa.border_pixel = xdev->borderColor;
  421.         xswa.colormap = xdev->cmap;
  422.         xdev->win = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
  423.                       sizehints.x, sizehints.y,        /* upper left */
  424.                       xdev->width, xdev->height,
  425.                       xdev->borderWidth,
  426.                       xdev->vinfo->depth,
  427.                       InputOutput,    /* class        */
  428.                       xdev->vinfo->visual,    /* visual */
  429.                       CWEventMask | CWBackPixel |
  430.                       CWBorderPixel | CWColormap,
  431.                       &xswa);
  432.         XStoreName(xdev->dpy, xdev->win, "ghostscript");
  433.         XSetWMNormalHints(xdev->dpy, xdev->win, &sizehints);
  434.         wm_hints.flags = InputHint;
  435.         wm_hints.input = False;
  436.         XSetWMHints(xdev->dpy, xdev->win, &wm_hints);    /* avoid input focus */
  437.     }
  438.     }
  439.     /***
  440.      *** According to Ricard Torres (torres@upf.es), we have to wait until here
  441.      *** to close the toolkit connection, which we formerly did
  442.      *** just after the calls on XAllocColor above.  I suspect that
  443.      *** this will cause things to be left dangling if an error occurs
  444.      *** anywhere in the above code, but I'm willing to let users
  445.      *** fight over fixing it, since I have no idea what's right.
  446.      ***/
  447.  
  448.     /* And close the toolkit connection. */
  449.     XtDestroyWidget(toplevel);
  450.     XtCloseDisplay(dpy);
  451.     XtDestroyApplicationContext(app_con);
  452.  
  453.     xdev->ht.pixmap = (Pixmap) 0;
  454.     xdev->ht.id = gx_no_bitmap_id;;
  455.     xdev->fill_style = FillSolid;
  456.     xdev->function = GXcopy;
  457.     xdev->fid = (Font) 0;
  458.  
  459.     /* Set up a graphics context */
  460.     xdev->gc = XCreateGC(xdev->dpy, xdev->win, 0, (XGCValues *) NULL);
  461.     XSetFunction(xdev->dpy, xdev->gc, GXcopy);
  462.     XSetLineAttributes(xdev->dpy, xdev->gc, 0,
  463.                LineSolid, CapButt, JoinMiter);
  464.  
  465.     gdev_x_clear_window(xdev);
  466.  
  467.     if (!xdev->ghostview) {    /* Make the window appear. */
  468.     XMapWindow(xdev->dpy, xdev->win);
  469.  
  470.     /* Before anything else, do a flush and wait for */
  471.     /* an exposure event. */
  472.     XSync(xdev->dpy, False);
  473.     if (xdev->pwin == (Window) None) {    /* there isn't a next event for existing windows */
  474.         XNextEvent(xdev->dpy, &event);
  475.     }
  476.     /* Now turn off graphics exposure events so they don't queue up */
  477.     /* indefinitely.  Also, since we can't do anything about real */
  478.     /* Expose events, mask them out. */
  479.     XSetGraphicsExposures(xdev->dpy, xdev->gc, False);
  480.     XSelectInput(xdev->dpy, xdev->win, NoEventMask);
  481.     } else {
  482.     /* Create an unmapped window, that the window manager will ignore.
  483.      * This invisible window will be used to receive "next page"
  484.      * events from ghostview */
  485.     XSetWindowAttributes attributes;
  486.  
  487.     attributes.override_redirect = True;
  488.     xdev->mwin = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
  489.                    0, 0, 1, 1, 0, CopyFromParent,
  490.                    CopyFromParent, CopyFromParent,
  491.                    CWOverrideRedirect, &attributes);
  492.     xdev->NEXT = XInternAtom(xdev->dpy, "NEXT", False);
  493.     xdev->PAGE = XInternAtom(xdev->dpy, "PAGE", False);
  494.     xdev->DONE = XInternAtom(xdev->dpy, "DONE", False);
  495.     }
  496.  
  497.     xdev->ht.no_pixmap = XCreatePixmap(xdev->dpy, xdev->win, 1, 1,
  498.                        xdev->vinfo->depth);
  499.  
  500.     return 0;
  501. }
  502.  
  503. /* Set up or take down buffering in a RAM image. */
  504. private int
  505. x_set_buffer(gx_device_X * xdev)
  506. {
  507.     /*
  508.      * We must use the stable memory here, since the existence of the
  509.      * buffer is independent of save/restore.
  510.      */
  511.     gs_memory_t *mem = gs_memory_stable(xdev->memory);
  512.     bool buffered = xdev->MaxBitmap > 0;
  513.     const gx_device_procs *procs;
  514.  
  515.  setup:
  516.     if (buffered) {
  517.     /* We want to buffer. */
  518.     /* Check that we can set up a memory device. */
  519.     gx_device_memory *mdev = (gx_device_memory *)xdev->target;
  520.  
  521.     if (mdev == 0 || mdev->color_info.depth != xdev->color_info.depth) {
  522.         const gx_device_memory *mdproto =
  523.         gdev_mem_device_for_bits(xdev->color_info.depth);
  524.  
  525.         if (!mdproto) {
  526.         buffered = false;
  527.         goto setup;
  528.         }
  529.         if (mdev) {
  530.         /* Update the pointer we're about to overwrite. */
  531.         gx_device_set_target((gx_device_forward *)mdev, NULL);
  532.         } else {
  533.         mdev = gs_alloc_struct(mem, gx_device_memory,
  534.                        &st_device_memory, "memory device");
  535.         if (mdev == 0) {
  536.             buffered = false;
  537.             goto setup;
  538.         }
  539.         }
  540.         /*
  541.          * We want to forward image drawing to the memory device.
  542.          * That requires making the memory device forward its color
  543.          * mapping operations back to the X device, creating a circular
  544.          * pointer structure.  This is not a disaster, we just need to
  545.          * be aware that this is going on.
  546.          */
  547.         gs_make_mem_device(mdev, mdproto, mem, 0, (gx_device *)xdev);
  548.         gx_device_set_target((gx_device_forward *)xdev, (gx_device *)mdev);
  549.         xdev->is_buffered = true;
  550.     }
  551.     if (mdev->width != xdev->width || mdev->height != xdev->height) {
  552.         byte *buffer;
  553.         ulong space;
  554.  
  555.         space = gdev_mem_data_size(mdev, xdev->width, xdev->height);
  556.         if (space > xdev->MaxBitmap) {
  557.         buffered = false;
  558.         goto setup;
  559.         }
  560.         buffer =
  561.         (xdev->buffer ?
  562.          (byte *)gs_resize_object(mem, xdev->buffer, space, "buffer") :
  563.          gs_alloc_bytes(mem, space, "buffer"));
  564.         if (!buffer) {
  565.         buffered = false;
  566.         goto setup;
  567.         }
  568.         xdev->buffer_size = space;
  569.         xdev->buffer = buffer;
  570.         mdev->width = xdev->width;
  571.         mdev->height = xdev->height;
  572.         mdev->color_info = xdev->color_info;
  573.         mdev->base = xdev->buffer;
  574.         gdev_mem_open_scan_lines(mdev, xdev->height);
  575.     }
  576.     xdev->white = gx_device_white((gx_device *)xdev);
  577.     xdev->black = gx_device_black((gx_device *)xdev);
  578.     procs = &gs_bbox_device.procs;
  579.     } else {
  580.     /* Not buffering.  Release the buffer and memory device. */
  581.     gs_free_object(mem, xdev->buffer, "buffer");
  582.     xdev->buffer = 0;
  583.     xdev->buffer_size = 0;
  584.     if (!xdev->is_buffered)
  585.         return 0;
  586.     gx_device_set_target((gx_device_forward *)xdev->target, NULL);
  587.     gx_device_set_target((gx_device_forward *)xdev, NULL);
  588.     xdev->is_buffered = false;
  589.     procs = &gs_x11_device.procs;
  590.     }
  591.     if (dev_proc(xdev, fill_rectangle) != procs->fill_rectangle) {
  592. #define COPY_PROC(p) set_dev_proc(xdev, p, procs->p)
  593.     COPY_PROC(fill_rectangle);
  594.     COPY_PROC(copy_mono);
  595.     COPY_PROC(copy_color);
  596.     COPY_PROC(copy_alpha);
  597.     COPY_PROC(fill_path);
  598.     COPY_PROC(stroke_path);
  599.     COPY_PROC(fill_mask);
  600.     COPY_PROC(fill_trapezoid);
  601.     COPY_PROC(fill_parallelogram);
  602.     COPY_PROC(fill_triangle);
  603.     COPY_PROC(draw_thin_line);
  604.     COPY_PROC(strip_tile_rectangle);
  605.     COPY_PROC(strip_copy_rop);
  606.     COPY_PROC(begin_typed_image);
  607.     COPY_PROC(create_compositor);
  608.     COPY_PROC(text_begin);
  609. #undef COPY_PROC
  610.     if (xdev->is_buffered) {
  611.         gx_device_forward_fill_in_procs((gx_device_forward *)xdev);
  612.         xdev->box_procs = gdev_x_box_procs;
  613.         xdev->box_proc_data = xdev;
  614.     } else
  615.         gx_device_fill_in_procs((gx_device *)xdev);
  616.     }
  617.     return 0;
  618. }
  619.  
  620. /* Allocate the backing pixmap, if any, and clear the window. */
  621. void
  622. gdev_x_clear_window(gx_device_X * xdev)
  623. {
  624.     if (!xdev->ghostview) {
  625.     if (xdev->useBackingPixmap) {
  626.         if (xdev->bpixmap == 0) {
  627.         x_error_handler.oldhandler = XSetErrorHandler(x_catch_alloc);
  628.         x_error_handler.alloc_error = False;
  629.         xdev->bpixmap =
  630.             XCreatePixmap(xdev->dpy, xdev->win,
  631.                   xdev->width, xdev->height,
  632.                   xdev->vinfo->depth);
  633.         XSync(xdev->dpy, False);    /* Force the error */
  634.         if (x_error_handler.alloc_error) {
  635.             xdev->useBackingPixmap = False;
  636. #ifdef DEBUG
  637.             eprintf("Warning: Failed to allocated backing pixmap.\n");
  638. #endif
  639.             if (xdev->bpixmap) {
  640.             XFreePixmap(xdev->dpy, xdev->bpixmap);
  641.             xdev->bpixmap = None;
  642.             XSync(xdev->dpy, False);    /* Force the error */
  643.             }
  644.         }
  645.         x_error_handler.oldhandler =
  646.             XSetErrorHandler(x_error_handler.oldhandler);
  647.         }
  648.     } else {
  649.         if (xdev->bpixmap != 0) {
  650.         XFreePixmap(xdev->dpy, xdev->bpixmap);
  651.         xdev->bpixmap = (Pixmap) 0;
  652.         }
  653.     }
  654.     }
  655.     x_set_buffer(xdev);
  656.     /* Clear the destination pixmap to avoid initializing with garbage. */
  657.     xdev->dest = (xdev->bpixmap != (Pixmap) 0 ?
  658.           xdev->bpixmap : (Pixmap) xdev->win);
  659.     if (xdev->dest != (Pixmap) 0) {
  660.     XSetForeground(xdev->dpy, xdev->gc, xdev->background);
  661.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc,
  662.                0, 0, xdev->width, xdev->height);
  663.     }
  664.  
  665.     /* Clear the background pixmap to avoid initializing with garbage. */
  666.     if (xdev->bpixmap != (Pixmap) 0) {
  667.     if (!xdev->ghostview)
  668.         XSetWindowBackgroundPixmap(xdev->dpy, xdev->win, xdev->bpixmap);
  669.     XSetForeground(xdev->dpy, xdev->gc, xdev->background);
  670.     XFillRectangle(xdev->dpy, xdev->bpixmap, xdev->gc,
  671.                0, 0, xdev->width, xdev->height);
  672.     }
  673.     /* Initialize foreground and background colors */
  674.     xdev->back_color = xdev->background;
  675.     XSetBackground(xdev->dpy, xdev->gc, xdev->background);
  676.     xdev->fore_color = xdev->background;
  677.     XSetForeground(xdev->dpy, xdev->gc, xdev->background);
  678.     xdev->colors_or = xdev->colors_and = xdev->background;
  679. }
  680.  
  681. /* ------ Initialize font mapping ------ */
  682.  
  683. /* Extract the PostScript font name from the font map resource. */
  684. private const char *
  685. get_ps_name(const char **cpp, int *len)
  686. {
  687.     const char *ret;
  688.  
  689.     *len = 0;
  690.     /* skip over whitespace and newlines */
  691.     while (**cpp == ' ' || **cpp == '\t' || **cpp == '\n') {
  692.     (*cpp)++;
  693.     }
  694.     /* return font name up to ":", whitespace, or end of string */
  695.     if (**cpp == ':' || **cpp == '\0') {
  696.     return NULL;
  697.     }
  698.     ret = *cpp;
  699.     while (**cpp != ':' &&
  700.        **cpp != ' ' && **cpp != '\t' && **cpp != '\n' &&
  701.        **cpp != '\0') {
  702.     (*cpp)++;
  703.     (*len)++;
  704.     }
  705.     return ret;
  706. }
  707.  
  708. /* Extract the X11 font name from the font map resource. */
  709. private const char *
  710. get_x11_name(const char **cpp, int *len)
  711. {
  712.     const char *ret;
  713.     int dashes = 0;
  714.  
  715.     *len = 0;
  716.     /* skip over whitespace and the colon */
  717.     while (**cpp == ' ' || **cpp == '\t' ||
  718.        **cpp == ':') {
  719.     (*cpp)++;
  720.     }
  721.     /* return font name up to end of line or string */
  722.     if (**cpp == '\0' || **cpp == '\n') {
  723.     return NULL;
  724.     }
  725.     ret = *cpp;
  726.     while (dashes != 7 &&
  727.        **cpp != '\0' && **cpp != '\n') {
  728.     if (**cpp == '-')
  729.         dashes++;
  730.     (*cpp)++;
  731.     (*len)++;
  732.     }
  733.     while (**cpp != '\0' && **cpp != '\n') {
  734.     (*cpp)++;
  735.     }
  736.     if (dashes != 7)
  737.     return NULL;
  738.     return ret;
  739. }
  740.  
  741. /* Scan one resource and build font map records. */
  742. private void
  743. scan_font_resource(const char *resource, x11fontmap **pmaps, gs_memory_t *mem)
  744. {
  745.     const char *ps_name;
  746.     const char *x11_name;
  747.     int ps_name_len;
  748.     int x11_name_len;
  749.     x11fontmap *font;
  750.     const char *cp = resource;
  751.  
  752.     while ((ps_name = get_ps_name(&cp, &ps_name_len)) != 0) {
  753.     x11_name = get_x11_name(&cp, &x11_name_len);
  754.     if (x11_name) {
  755.         font = gs_alloc_struct(mem, x11fontmap, &st_x11fontmap,
  756.                    "scan_font_resource(font)");
  757.         if (font == NULL)
  758.         continue;
  759.         font->ps_name = (char *)
  760.         gs_alloc_byte_array(mem, ps_name_len + 1, sizeof(char),
  761.                     "scan_font_resource(ps_name)");
  762.         if (font->ps_name == NULL) {
  763.         gs_free_object(mem, font, "scan_font_resource(font)");
  764.         continue;
  765.         }
  766.         strncpy(font->ps_name, ps_name, ps_name_len);
  767.         font->ps_name[ps_name_len] = '\0';
  768.         font->x11_name = (char *)
  769.         gs_alloc_byte_array(mem, x11_name_len, sizeof(char),
  770.                     "scan_font_resource(x11_name)");
  771.         if (font->x11_name == NULL) {
  772.         gs_free_object(mem, font->ps_name,
  773.                    "scan_font_resource(ps_name)");
  774.         gs_free_object(mem, font, "scan_font_resource(font)");
  775.         continue;
  776.         }
  777.         strncpy(font->x11_name, x11_name, x11_name_len - 1);
  778.         font->x11_name[x11_name_len - 1] = '\0';
  779.         font->std.names = NULL;
  780.         font->std.count = -1;
  781.         font->iso.names = NULL;
  782.         font->iso.count = -1;
  783.         font->next = *pmaps;
  784.         *pmaps = font;
  785.     }
  786.     }
  787. }
  788.  
  789. /* Scan all the font resources and set up the maps. */
  790. private void
  791. gdev_x_setup_fontmap(gx_device_X * xdev)
  792. {
  793.     if (!xdev->useXFonts)
  794.     return;            /* If no external fonts, don't bother */
  795.  
  796.     scan_font_resource(xdev->regularFonts, &xdev->regular_fonts, xdev->memory);
  797.     scan_font_resource(xdev->symbolFonts, &xdev->symbol_fonts, xdev->memory);
  798.     scan_font_resource(xdev->dingbatFonts, &xdev->dingbat_fonts, xdev->memory);
  799. }
  800.  
  801. /* Clean up the instance after making a copy. */
  802. int
  803. gdev_x_finish_copydevice(gx_device *dev, const gx_device *from_dev)
  804. {
  805.     gx_device_X *xdev = (gx_device_X *) dev;
  806.  
  807.     /* Mark the new instance as closed. */
  808.     xdev->is_open = false;
  809.  
  810.     /* Prevent dangling references from the *_fonts lists. */
  811.     xdev->regular_fonts = 0;
  812.     xdev->symbol_fonts = 0;
  813.     xdev->dingbat_fonts = 0;
  814.  
  815.     /* Clear all other pointers. */
  816.     xdev->target = 0;
  817.     xdev->buffer = 0;
  818.     xdev->dpy = 0;
  819.     xdev->scr = 0;
  820.     xdev->vinfo = 0;
  821.  
  822.     /* Clear pointer-like parameters. */
  823.     xdev->win = (Window)None;
  824.     xdev->bpixmap = (Pixmap)0;
  825.     xdev->dest = (Pixmap)0;
  826.     xdev->cp.pixmap = (Pixmap)0;
  827.     xdev->ht.pixmap = (Pixmap)0;
  828.  
  829.     /* Reset pointer-related parameters. */
  830.     xdev->is_buffered = false;
  831.     /* See x_set_buffer for why we do this: */
  832.     set_dev_proc(xdev, fill_rectangle,
  833.          dev_proc(&gs_x11_device, fill_rectangle));
  834.  
  835.     return 0;
  836. }
  837.  
  838. /* ---------------- Get/put parameters ---------------- */
  839.  
  840. /* Get the device parameters.  See below. */
  841. int
  842. gdev_x_get_params(gx_device * dev, gs_param_list * plist)
  843. {
  844.     gx_device_X *xdev = (gx_device_X *) dev;
  845.     int code = gx_default_get_params(dev, plist);
  846.     long id = (long)xdev->pwin;
  847.  
  848.     if (code < 0 ||
  849.     (code = param_write_long(plist, "WindowID", &id)) < 0 ||
  850.     (code = param_write_bool(plist, ".IsPageDevice", &xdev->IsPageDevice)) < 0 ||
  851.     (code = param_write_long(plist, "MaxBitmap", &xdev->MaxBitmap)) < 0 ||
  852.     (code = param_write_int(plist, "MaxTempPixmap", &xdev->MaxTempPixmap)) < 0 ||
  853.     (code = param_write_int(plist, "MaxTempImage", &xdev->MaxTempImage)) < 0 ||
  854.     (code = param_write_int(plist, "MaxBufferedTotal", &xdev->MaxBufferedTotal)) < 0 ||
  855.     (code = param_write_int(plist, "MaxBufferedArea", &xdev->MaxBufferedArea)) < 0 ||
  856.     (code = param_write_int(plist, "MaxBufferedCount", &xdev->MaxBufferedCount)) < 0
  857.     )
  858.     DO_NOTHING;
  859.     return code;
  860. }
  861.  
  862. /* Set the device parameters.  We reimplement this so we can resize */
  863. /* the window and avoid closing and reopening the device, and to add */
  864. /* .IsPageDevice. */
  865. int
  866. gdev_x_put_params(gx_device * dev, gs_param_list * plist)
  867. {
  868.     gx_device_X *xdev = (gx_device_X *) dev;
  869.     /*
  870.      * Provide copies of values of parameters being set:
  871.      * is_open, width, height, HWResolution, IsPageDevice, Max*.
  872.      */
  873.     gx_device_X values;
  874.  
  875.     long pwin = (long)xdev->pwin;
  876.     bool save_is_page = xdev->IsPageDevice;
  877.     int ecode = 0, code;
  878.     bool clear_window = false;
  879.  
  880.     values = *xdev;
  881.  
  882.     /* Handle extra parameters */
  883.  
  884.     ecode = param_put_long(plist, "WindowID", &pwin, ecode);
  885.     ecode = param_put_bool(plist, ".IsPageDevice", &values.IsPageDevice, ecode);
  886.     ecode = param_put_long(plist, "MaxBitmap", &values.MaxBitmap, ecode);
  887.     ecode = param_put_int(plist, "MaxTempPixmap", &values.MaxTempPixmap, ecode);
  888.     ecode = param_put_int(plist, "MaxTempImage", &values.MaxTempImage, ecode);
  889.     ecode = param_put_int(plist, "MaxBufferedTotal", &values.MaxBufferedTotal, ecode);
  890.     ecode = param_put_int(plist, "MaxBufferedArea", &values.MaxBufferedArea, ecode);
  891.     ecode = param_put_int(plist, "MaxBufferedCount", &values.MaxBufferedCount, ecode);
  892.  
  893.     if (ecode < 0)
  894.     return ecode;
  895.  
  896.     /* Unless we specified a new window ID, */
  897.     /* prevent gx_default_put_params from closing the device. */
  898.     if (pwin == (long)xdev->pwin)
  899.     dev->is_open = false;
  900.     xdev->IsPageDevice = values.IsPageDevice;
  901.     code = gx_default_put_params(dev, plist);
  902.     dev->is_open = values.is_open; /* saved value */
  903.     if (code < 0) {        /* Undo setting of .IsPageDevice */
  904.     xdev->IsPageDevice = save_is_page;
  905.     return code;
  906.     }
  907.     if (pwin != (long)xdev->pwin) {
  908.     if (xdev->is_open)
  909.         gs_closedevice(dev);
  910.     xdev->pwin = (Window) pwin;
  911.     }
  912.     /* If the device is open, resize the window. */
  913.     /* Don't do this if Ghostview is active. */
  914.     if (xdev->is_open && !xdev->ghostview &&
  915.     (dev->width != values.width || dev->height != values.height ||
  916.      dev->HWResolution[0] != values.HWResolution[0] ||
  917.      dev->HWResolution[1] != values.HWResolution[1])
  918.     ) {
  919.     int dw = dev->width - values.width;
  920.     int dh = dev->height - values.height;
  921.     double qx = dev->HWResolution[0] / values.HWResolution[0];
  922.     double qy = dev->HWResolution[1] / values.HWResolution[1];
  923.  
  924.     if (dw || dh) {
  925.         XResizeWindow(xdev->dpy, xdev->win,
  926.               dev->width, dev->height);
  927.         if (xdev->bpixmap != (Pixmap) 0) {
  928.         XFreePixmap(xdev->dpy, xdev->bpixmap);
  929.         xdev->bpixmap = (Pixmap) 0;
  930.         }
  931.         xdev->dest = 0;
  932.         clear_window = true;
  933.     }
  934.     /* Attempt to update the initial matrix in a sensible way. */
  935.     /* The whole handling of the initial matrix is a hack! */
  936.     if (xdev->initial_matrix.xy == 0) {
  937.         if (xdev->initial_matrix.xx < 0) {    /* 180 degree rotation */
  938.         xdev->initial_matrix.tx += dw;
  939.         } else {        /* no rotation */
  940.         xdev->initial_matrix.ty += dh;
  941.         }
  942.     } else {
  943.         if (xdev->initial_matrix.xy < 0) {    /* 90 degree rotation */
  944.         xdev->initial_matrix.tx += dh;
  945.         xdev->initial_matrix.ty += dw;
  946.         } else {        /* 270 degree rotation */
  947.         }
  948.     }
  949.     xdev->initial_matrix.xx *= qx;
  950.     xdev->initial_matrix.xy *= qx;
  951.     xdev->initial_matrix.yx *= qy;
  952.     xdev->initial_matrix.yy *= qy;
  953.     }
  954.     xdev->MaxTempPixmap = values.MaxTempPixmap;
  955.     xdev->MaxTempImage = values.MaxTempImage;
  956.     xdev->MaxBufferedTotal = values.MaxBufferedTotal;
  957.     xdev->MaxBufferedArea = values.MaxBufferedArea;
  958.     xdev->MaxBufferedCount = values.MaxBufferedCount;
  959.     if (clear_window || xdev->MaxBitmap != values.MaxBitmap) {
  960.     /****** DO MORE FOR RESETTING MaxBitmap ******/
  961.     xdev->MaxBitmap = values.MaxBitmap;
  962.     if (xdev->is_open)
  963.         gdev_x_clear_window(xdev);
  964.     }
  965.     return 0;
  966. }
  967.  
  968. /* ---------------- Closing/finalization ---------------- */
  969.  
  970. /* Free fonts when closing the device. */
  971. private void
  972. free_x_fontmaps(x11fontmap **pmaps, gs_memory_t *mem)
  973. {
  974.     while (*pmaps) {
  975.     x11fontmap *font = *pmaps;
  976.  
  977.     *pmaps = font->next;
  978.     if (font->std.names)
  979.         XFreeFontNames(font->std.names);
  980.     if (font->iso.names)
  981.         XFreeFontNames(font->iso.names);
  982.     gs_free_object(mem, font->x11_name, "free_x_fontmaps(x11_name)");
  983.     gs_free_object(mem, font->ps_name, "free_x_fontmaps(ps_name)");
  984.     gs_free_object(mem, font, "free_x_fontmaps(font)");
  985.     }
  986. }
  987.  
  988. /* Close the device. */
  989. int
  990. gdev_x_close(gx_device_X *xdev)
  991. {
  992.     if (xdev->ghostview)
  993.     gdev_x_send_event(xdev, xdev->DONE);
  994.     if (xdev->vinfo) {
  995.     XFree((char *)xdev->vinfo);
  996.     xdev->vinfo = NULL;
  997.     }
  998.     gdev_x_free_colors(xdev);
  999.     free_x_fontmaps(&xdev->dingbat_fonts, xdev->memory);
  1000.     free_x_fontmaps(&xdev->symbol_fonts, xdev->memory);
  1001.     free_x_fontmaps(&xdev->regular_fonts, xdev->memory);
  1002.     if (xdev->cmap != DefaultColormapOfScreen(xdev->scr))
  1003.     XFreeColormap(xdev->dpy, xdev->cmap);
  1004.     XCloseDisplay(xdev->dpy);
  1005.     return 0;
  1006. }
  1007.